#include <QHttp>
#include <QDebug>
#include <QList>
#include <QFile>
#include <QTextStream>
#include <QTextCodec>
#include <QDate>

#include "rsscontainer.h"
#include "rsschannel.h"
#include "rssleaf.h"
#include "xmlparser.h"
#include "qrssglobals.h"


RssContainer::RssContainer( QObject* parent ) 
	: QObject( parent )
	, m_state( EIDLE )
{
	initResource();

	m_httpHandler = new HttpHandler( *this, this );
	m_curChannel = NULL;
	
	m_xmlParser = new XmlParser();

	//FIXME
	QTextCodec* codec;
	codec = QTextCodec::codecForName( "ISO 8859-2" );
	QTextCodec::setCodecForCStrings(codec);

	m_xmlReader.setContentHandler( m_xmlParser );
	m_xmlReader.setErrorHandler( this );

	//xml
	connect( m_xmlParser, SIGNAL( documentEnd( RssChannel* )), this, SLOT( documentEnd( RssChannel* )));

	m_parser = new HttpParser( NULL, this );

	connect( m_parser, SIGNAL( linkParsed( const QString& )), this, SLOT( httpItemParserd(const QString& )));
	connect( m_parser, SIGNAL( parseErr( int )), this, SLOT( httpItemParsingError( int )));
	
	m_firstData = true;
	m_isUpdating = false;
	m_monthsName << "Jan" << "Feb" << "Mar" <<  "Apr" <<  "May" << "Jun" << "Jul" << "Aug" << "Sep" << "Oct" <<  "Nov" << "Dec";
	m_hosts << "rapidshare.com" << "uploadjockey.com";
	update();

	m_timerId = startTimer(5*60000);// 5minutes
}

RssContainer::~RssContainer()
{
	while(!m_channelsList.isEmpty())
		delete m_channelsList.takeFirst();

	delete m_httpHandler;
}

void RssContainer::initResource()
{
	m_resource.insert(_leafItem, qMakePair(QString("item"), QString("entry")));
	m_resource.insert(_leafDate, qMakePair(QString("pubDate"), QString("published")));
	m_resource.insert(_leafTitle, qMakePair(QString("title"), QString("title")));
	m_resource.insert(_leafLink, qMakePair(QString("link"), QString("uri")));
	m_resource.insert(_leafDescription, qMakePair(QString("description"), QString("content")));
}

QString RssContainer::getResource( const QString& key, QRssFType& type)
{
	if( type == _eChannel )
		return m_resource.find( key )->first;
	else
		return m_resource.find( key )->second;
}

void RssContainer::addCurChannel()
{
	Q_ASSERT( false );
	m_channelsList.append( m_curChannel );
	//FIXME:
//	emit(channelAdded( m_curChannel->name(), m_curChannel->countUnreaded(), false ));
	getChannelFeeds( m_channelsList.count() - 1 );
}

void RssContainer::addChannel( QString& url )
{
	QUrl qurl( url );
	if( qurl.isValid( ))
	{
		m_state = EXMLPARSING;
		m_httpHandler->get( qurl );
	}
	else
		qDebug() << "Invalid url passed: " << qurl;
}

void RssContainer::deleteChannel( int ind )
{
	RssChannel* channel = m_channelsList.at( ind );
	m_channelsList.removeAt( ind );
	delete channel;
}
/*
void RssContainer::newItemParsed( QString& itemTitle, QString& itemDesc, QString& itemDate, QString& link )
{
	QDateTime date =  parseDate( itemDate );

	//We don't have to add new item if it's already on the list
	//Check pubDate of items first
	bool onTheList = false;

	if( m_isUpdating )
	{
		//\FIXME:
		//onTheList = m_curChannel->isItemAdded( date, &itemTitle );
	}

	if( !onTheList )
	{
		QUrl url = QUrl( link );
		//\FIXME:
		//m_curChannel->addItem( itemTitle, itemDesc, date, url );
		
		//emit this signal only if channel is already on the list.
		if( m_channelsList.indexOf( m_curChannel ) != -1 )
			emit( itemAdded( m_channelsList.indexOf( m_curChannel ), eNew, itemTitle, date ));
	}
}
*/
void RssContainer::documentEnd( RssChannel* channel )
{
	Q_ASSERT( channel );

	if( !m_isUpdating )
	{
		m_channelsList.append( channel );
		QRssFType type = channel->type();
		QString title = getResource( _leafTitle, type );
		QString date = getResource( _leafDate, type );
		emit( channelAdded( channel->value( title ), channel->countUnreaded(), false ));
		int ind = m_channelsList.indexOf( channel );
		foreach( RssLeaf* leaf, channel->leaves() )
		{
			emit( itemAdded( ind , eNew, leaf->value( title ), parseDate( leaf->value( date ), type)) );
		}
	}
}

QString RssContainer::parseDate( QString itemDate, QRssFType type )
{
	
	if( type == _eChannel )
	{
		//Tue, 24 Jun 2008 23:26:24 +0200
		itemDate = itemDate.trimmed();
		int i = itemDate.indexOf(" ") + 1;
		int j = itemDate.indexOf("+");
		if( j == -1 )
		{
			j = itemDate.lastIndexOf( " " );
		}
		
		j = j - 1 - i;
		
		itemDate = itemDate.mid( i,j );
		
		int ind = 1;
		foreach( QString month, m_monthsName )
		{
			if(( i = itemDate.indexOf( month, 0, Qt::CaseInsensitive )) != -1 )
				itemDate.replace( i, 3, QDate::shortMonthName( ind ));
			ind++;
		}
		return itemDate;
	}
	else if( type == _eFeed )
	{
	// "2008-10-06T10:49:50.312+03:00"
		int j = itemDate.indexOf("+");
		itemDate = itemDate.left(j);
	// 	2008-10-06T10:49:50.312
		QString format("yyyy-MM-ddThh:mm:ss.zzz");
		QDateTime date = QDateTime::fromString( itemDate, format );
		return date.toString( _dateFormat );
	}
}

QString RssContainer::getItemDescription( int channelId, int ind )
{
	Q_ASSERT( channelId < m_channelsList.count( ));
	RssChannel* channel = m_channelsList.at( channelId );
	const RssLeaf leaf = channel->leaf( ind );
	QRssFType type = channel->type();
	QString desc;
	desc = "<p><a href=\"" + leaf.value( getResource( _leafLink, type ))
							+ "\">" + leaf.value( getResource( _leafTitle, type ))
							+ "</a></p><br>" + leaf.value( getResource( _leafDescription, type ));
	return desc;
}

void RssContainer::getChannelFeeds( int ind )
{
	Q_ASSERT( ind < m_channelsList.count( ));
	RssChannel* channel = m_channelsList.at( ind );
	QRssFType type = channel->type();	
	QString title = getResource( _leafTitle, type );
	QString date = getResource( _leafDate, type );
	foreach( RssLeaf* item, channel->leaves())
	{
		emit( itemAdded( ind, item->state(), item->value(title), parseDate( item->value( date ), type )));
	}
}

QUrl RssContainer::getChannelUrl( int ind )
{
	Q_ASSERT( ind < m_channelsList.count( ));
	RssChannel* channel = m_channelsList.at( ind );
	QRssFType type = channel->type();
	return QUrl( channel->value( getResource(_leafLink, type)));
}

void RssContainer::storeData()
{
	qDebug() << __LOG_FNAME__ ;
	QFile file( CNFNAME );

	if( file.open( QIODevice::WriteOnly | QIODevice::Truncate ))
	{
		QTextStream stream( &file );

		stream << m_channelsList.count() << "\n";
		qDebug() << m_channelsList.count() << "saved";

		foreach( RssChannel* channel, m_channelsList )
		{
			channel->externalize( stream );
		}
		stream << RSSCNFEND << "\n";
		qDebug() << RSSCNFEND << "\n saved";

		file.close();
	}

	if( m_parsedLinks.count() > 0 )
	{
		QFile file2("links.txt");
		if( file2.open( QIODevice::WriteOnly | QIODevice::Truncate ))
		{
			QTextStream stream( &file2 );
			foreach(QString txt, m_parsedLinks )
				stream << txt << "\n";
		}
		file2.close();
	}
}

void RssContainer::loadData()
{
	qDebug() << __LOG_FNAME__;
	
	QFile file( CNFNAME );
	if( file.exists( ))
	{
		if( file.open( QIODevice::ReadOnly ))
		{
			QTextStream stream( &file );
			QString line = stream.readLine();
			bool ok = false;
			
			int count = line.toInt( &ok );
			if( ok )
			{
				RssChannel* channel;
				QRssFType type;
				for( int i = 0; i < count; i++ )
				{
					channel = new RssChannel();
					channel->internalize( stream );
					m_channelsList.append( channel );
					type = channel->type();
					emit( channelAdded( channel->value( getResource(_leafTitle, type)), channel->countUnreaded(), true ));
				}
				if( count > 0 )
					getChannelFeeds( 0 );
			}
			file.close();
		}
	}
}

void RssContainer::update()
{
	qDebug() << __LOG_FNAME__;
	//we have to wait for the first channel refreshing before we hit the next one
	
	if( m_channelsList.count() > 0 )
	{
		m_isUpdating = true;
		m_channelsIterator = m_channelsList.begin();
		m_curChannel = *m_channelsIterator;
		refreshCurrentChannel();
		++m_channelsIterator;
	}
}

void RssContainer::refreshCurrentChannel()
{
	//\FIXME:
//	QUrl qurl = m_curChannel->url();
//	m_xmlParser->setItemType( XmlParser::_rssGetChannel );
	m_state = EXMLPARSING;
//	m_httpHandler->get( qurl );
//	m_http->setHost(qurl.host());
//	m_currentContId = m_http->get(qurl.path());
}

void RssContainer::setItemState( int channelId, int ind, ItemState state )
{
	m_channelsList.at( channelId )->setItemState( ind, state );
}

//FROM QXmlErrorHandler
bool RssContainer::error( const QXmlParseException & exception )
{
	qDebug() << __LOG_FNAME__;
	qDebug() << exception.message();
	return true;
}

bool RssContainer::fatalError( const QXmlParseException & exception )
{
	qDebug() << __LOG_FNAME__;
	qDebug() << exception.message();
	emit(displayError( exception.message( )));
	return false;
}
bool RssContainer::warning( const QXmlParseException & exception )
{
	qDebug() << __LOG_FNAME__;
	qDebug() << exception.message();
	return true;
}
QString RssContainer::errorString() const
{
	QString msg = tr( "Xml error occurred" );
	return msg;
}

void RssContainer::timerEvent( QTimerEvent *event )
{
	qDebug() << __LOG_FNAME__;
	update();
}

void RssContainer::readAll( int channelId )
{
	m_channelsList.at( channelId )->readAll( );
}

QString	RssContainer::getChannelDescription( int ind )
{
	Q_ASSERT( ind < m_channelsList.count( ));
	QString desc;
	RssChannel* channel = m_channelsList.at(ind);
	QRssFType type = channel->type();
	//\TODO: add more details here
	desc = "<b>" +channel->value( getResource( _leafTitle, type ))
		+ "</b><br>" + channel->value( getResource( _leafLink, type ));

	return desc;
}

void RssContainer::handleResponse( QByteArray data )
{
	if( m_state == EXMLPARSING )
	{
		bool ok = true;
		m_xmlInput.setData( data );
		
		if( m_firstData )
		{
			ok = m_xmlReader.parse( &m_xmlInput, true );
			m_firstData = false;
		}
		else
			ok = m_xmlReader.parseContinue();
		
		if ( !ok )
		{
			m_httpHandler->abort();
			m_state = EIDLE;
		}
	}
}

//TODO: add string param to use it in msg
void RssContainer::error( int errCode )
{
	QString note = QString( "HTTP ERROR %1" ).arg( errCode );
	emit( displayError( note ));		
	m_state = EIDLE;
}

void RssContainer::requestFinished( bool error )
{
	if( m_state == EXMLPARSING )
	{
		if( !error )
		{
			if( !m_xmlReader.parseContinue( ))
				qWarning("Parse error at the end of input.");
		}
	}
}

void RssContainer::progress( int done, int total )
{
	//TODO: display progress bar on status bar
	qDebug() << done << "/" << total;
}

void RssContainer::httpDone()
{
	if( m_state == EXMLPARSING )
	{
		m_firstData = true;
		if( m_isUpdating )
		{
			if( m_channelsIterator != m_channelsList.end( ))
			{
				m_curChannel = *m_channelsIterator;
				refreshCurrentChannel();
				++m_channelsIterator;
			}
			else
				m_isUpdating = false;
		}
		m_state = EIDLE;
	}
}

void RssContainer::httpResponseHeaderReceived( const QHttpResponseHeader & resp )
{
	//TODO: set some cookie here ?
}

void RssContainer::markForParse( int ind )
{
	m_channelsList[ind]->parserMark( );
}

void RssContainer::parseLinks()
{
	QList < const QString* > list;

	foreach( RssChannel* channel, m_channelsList )
	{
		if( channel->parse( ))
		{
			foreach( RssLeaf* item, channel->leaves( ))
			{
				//list.append( &item->value( _leafDescription ));
			}
		}
	}
	m_parser->parse( list );
}

void RssContainer::httpItemParserd(const QString& url)
{
	//TODO: handle parsed items then share it using dbus
	qDebug() << url;
	m_parsedLinks.append( url );
}

void RssContainer::httpItemParsingError( int err )
{
	//FIXME: error ( "parsing error, err );
	error( err );
}
//EOF
